import * as $ from 'jquery';
import * as ol from 'openlayers';

export class CommonTools {
   X_PI = Math.PI * 3000.0 / 180.0;
   AA = 6378245.0;
   EE = 0.00669342162296594323;

   AMAP_REGEO_URL = 'http://restapi.amap.com/v3/geocode/regeo';
   AMAP_GEO_URL = 'http://restapi.amap.com/v3/geocode/geo';
   AMAP_PLACE_URL = 'http://restapi.amap.com/v3/place/text';
   AMAP_KEY = '370c732461b3efca34dbdd688400d706';

  /**
   * 判断一个点是否在多边形点集内部
   * @param points 多边形坐标集合
   * @param testPoint 测试点坐标
   */
 insidePolygon(points, testPoint) {
    let x = testPoint[0], y = testPoint[1];
    let inside = false;
    for (let i = 0, j = points.length - 1; i < points.length; j = i++) {
      let xi = points[i][0], yi = points[i][1];
      let xj = points[j][0], yj = points[j][1];

      let intersect = ((yi > y) != (yj > y))
        && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
      if (intersect) inside = !inside;
    }
    return inside;
  }

  /**
   * 判断点是否在一个圆内
   * @param point 待判断点坐标
   * @param center 圆心坐标
   * @param radius 圆的半径
   */
 pointInsideCircle(point, center, radius) {
    if (radius === 0) return false;
    let dx = center[0] - point[0];
    let dy = center[1] - point[1];
    return dx * dx + dy * dy <= radius * radius;
  }

  /**
   * 逆地理编码，根据输入经纬度坐标，解析该位置的地址信息
   * @param position 经纬度坐标信息
   * @param isGCJ 坐标是否是国测局02坐标系加密坐标
   * @param callback 查询回调函数
   */
 getAddressByPoint(position, isGCJ, callback) {
    let location;
    if (isGCJ) {
      location = '' + position[0] + ',' + position[1];
    } else {
      let coors = this.WGS84_To_GCJ02(position[0], position[1]);
      location = '' + coors[0] + ',' + coors[1];
    }

    let radius = 1000;
    let requestUrl = `${this.AMAP_REGEO_URL}?key=${this.AMAP_KEY}&location=${location}&poitype=&radius=${radius}
                         &extensions=base&batch=false&roadlevel=0`;
    $.post(requestUrl, null, (result) => {
      let address = {};
      if (result.infocode == "10000") {
        address['address'] = result.regeocode.formatted_address;
        address['addressComponent'] = result.regeocode.addressComponent;
        callback(address);
      } else {
        console.log('逆地理解析失败');
        callback(null);
      }
    })
  }

  /**
   * 地理编码，根据输入的地址信息，解析出坐标，并按照规定格式返回结果
   * @param address 地址信息
   * @param isGCJ 是否返回经过GCJ02坐标系加密的坐标
   * @param callback 回调函数
   */
 getPointByAddress(address, isGCJ, callback) {
    let requestUrl = `${this.AMAP_GEO_URL}?key=${this.AMAP_KEY}&address=${address}&city=`;
    $.get(requestUrl, (result) => {
      let geoLists;
      if (result.infocode == "10000") {
        const geoData = result.geocodes;
        geoData.forEach((value, index) => {
          let geoItemData;
          let position = value['location'].split(',').map();
          if (!isGCJ) {
            position = this.GCJ02_TO_WGS84(position[0], position[1]);
          }
          let coordsXY = this.WGS84_To_WEBMERCATOR(position);
          geoItemData = {
            className: 'geo',
            data: { name: value.formatted_address, id: index, geometry: { type: 'point', points: [{ x: coordsXY[0], y: coordsXY[1] }] } }
          }
          geoLists.push(geoItemData);
        })
        callback(geoLists);
      } else {
        console.log('地理解析失败');
        callback(null);
      }
    })
  }


 getPlaces(searchBody, isGCJ, callback) {
    let requestUrl = `${this.AMAP_PLACE_URL}?key=${this.AMAP_KEY}&keywords=${searchBody.keywords}&type=&city=${searchBody.city}
                          &children=0&offset=${searchBody.itemsPerPage}&page=${searchBody.page}&extensions=base`;
    $.get(requestUrl, (result) => {
      let placeData = {};
      if (result.infocode == '10000') {
        placeData['count'] = result.count;
        placeData['page'] = searchBody.page;
        let poiDatas= [];
        const poiLists = result.pois;
        poiLists.forEach((value) => {
          let poi;
          let position = value['location'].split(',').map(Number);
          if (!isGCJ) {
            position = this.GCJ02_TO_WGS84(position[0], position[1]);
          }
          let coordsXY = this.WGS84_To_WEBMERCATOR(position);
          poi = {
            className: 'poi',
            data: {
              name: value.name,
              id: value.id,
              geometry: { type: 'point', points: [{ x: coordsXY[0], y: coordsXY[1] }] },
              address: value.address,
              type: value.type,
              typecode: value.typecode,
              tel: value.tel
            },
          }
          poiDatas.push(poi);
        });
        placeData['data'] = poiDatas;
        callback(placeData);
      } else {
        console.log('POI数据请求失败');
        callback(null);
      }
    })
  }
  /**
   * WGS84经纬度坐标转换为网络墨卡托投影坐标
   * @param position 坐标数组[lng, lat]
   */
 WGS84_To_WEBMERCATOR(position) {
    const coors = ol.proj.transform(position, 'EPSG:4326', 'EPSG:3857');
    return coors;
  }

  /**
   *,坐标转换为WGS84经纬度坐标
   * @param position 坐标数组[x, y]
   */
 WEBMERCATOR_To_WGS84(position) {
    const coors = ol.proj.transform(position, 'EPSG:3857', 'EPSG:4326');
    return coors;
  }

  /**
   * WGS84经纬度坐标转换为国测局加密经纬度坐标
   * @param lng 经度
   * @param lat 纬度
   */
 WGS84_To_GCJ02(lng, lat) {
    if (this.out_of_china(lng, lat)) {
      return [lng, lat];
    } else {
      let dlat = this.transformlat(lng - 105.0, lat - 35.0);
      let dlng = this.transformlng(lng - 105.0, lat - 35.0);
      let radlat = lat / 180.0 * Math.PI;
      let magic = Math.sin(radlat);
      magic = 1 - this.EE * magic * magic;
      let sqrtmagic = Math.sqrt(magic);
      dlat = (dlat * 180.0) / ((this.AA * (1 - this.EE)) / (magic * sqrtmagic) * Math.PI);
      dlng = (dlng * 180.0) / (this.AA / sqrtmagic * Math.cos(radlat) * Math.PI);
      let mglat = lat + dlat;
      let mglng = lng + dlng;
      return [mglng, mglat]
    }
  }

  /**
   * 国测局02经纬度坐标转换为WGS84经纬度坐标
   * @param lng 经度
   * @param lat 纬度
   */
 GCJ02_TO_WGS84(lng, lat) {
    if (this.out_of_china(lng, lat)) {
      return [lng, lat];
    } else {
      let dlat = this.transformlat(lng - 105.0, lat - 35.0);
      let dlng = this.transformlng(lng - 105.0, lat - 35.0);
      let radlat = lat / 180.0 * Math.PI;
      let magic = Math.sin(radlat);
      magic = 1 - this.EE * magic * magic;
      let sqrtmagic = Math.sqrt(magic);
      dlat = (dlat * 180.0) / ((this.AA * (1 - this.EE)) / (magic * sqrtmagic) * Math.PI);
      dlng = (dlng * 180.0) / (this.AA / sqrtmagic * Math.cos(radlat) * Math.PI);
      let mglat = lat + dlat;
      let mglng = lng + dlng;
      return [lng * 2 - mglng, lat * 2 - mglat]
    }
  }

  /**
   * 百度地图09坐标系转换为国测局02经纬度坐标系
   * @param bd_lng 经度
   * @param bd_lat 纬度
   */
 BD09_To_GCJ02(bd_lng, bd_lat) {
    let x = bd_lng - 0.0065;
    let y = bd_lat - 0.006;
    let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * this.X_PI);
    let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * this.X_PI);
    let gg_lng = z * Math.cos(theta);
    let gg_lat = z * Math.sin(theta);
    return [gg_lng, gg_lat]
  }

  /**
   * 国测局02经纬度坐标转换为百度地图09经纬度坐标
   * @param lng 经度
   * @param lat 纬度
   */
 GCJ02_To_BD09(lng, lat) {
    let z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * this.X_PI);
    let theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * this.X_PI);
    let bd_lng = z * Math.cos(theta) + 0.0065;
    let bd_lat = z * Math.sin(theta) + 0.006;
    return [bd_lng, bd_lat]
  }

   transformlat(lng, lat) {
    let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
    ret += (20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 * Math.sin(2.0 * lng * Math.PI)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(lat * Math.PI) + 40.0 * Math.sin(lat / 3.0 * Math.PI)) * 2.0 / 3.0;
    ret += (160.0 * Math.sin(lat / 12.0 * Math.PI) + 320 * Math.sin(lat * Math.PI / 30.0)) * 2.0 / 3.0;
    return ret;
  }

   transformlng(lng, lat) {
    let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
    ret += (20.0 * Math.sin(6.0 * lng * Math.PI) + 20.0 * Math.sin(2.0 * lng * Math.PI)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(lng * Math.PI) + 40.0 * Math.sin(lng / 3.0 * Math.PI)) * 2.0 / 3.0;
    ret += (150.0 * Math.sin(lng / 12.0 * Math.PI) + 300.0 * Math.sin(lng / 30.0 * Math.PI)) * 2.0 / 3.0;
    return ret;
  }

  /**
   * 判断该点是否在中国
   * @param lng 经度
   * @param lat 纬度
   */
   out_of_china(lng, lat) {
    return (lng < 72.004 || lng > 137.8347) || ((lat < 0.8293 || lat > 55.8271) || false);
  }
}